package org.msb.accentis.gui.views;

import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.msb.accentis.data.pojo.Account;
import org.msb.accentis.data.pojo.Category;
import org.msb.accentis.data.pojo.Individual;
import org.msb.accentis.data.pojo.Payee;
import org.msb.accentis.data.pojo.Transaction;
import org.msb.accentis.gui.models.PojoComboBoxModel;
import org.msb.accentis.gui.swing.DateFormattedTextField;
import org.msb.accentis.gui.swing.TwoDecimalTextField;

public abstract class AbstractTransactionEditorView extends JComponent {

	private DateFormattedTextField dateField;

	private JTextField referenceField;

	private TwoDecimalTextField amountField;

	private JComboBox<Individual> individualComboBox;

	private JTextField descriptionField;

	private TransactionEditor transactionEditor;

	private JComboBox<Category> categoryComboBox;

	private JComboBox<Category> subcategoryComboBox;

	private JComboBox<Payee> payeeComboBox;

	private JComboBox<Account> fromAccountComboBox;

	private JComboBox<Account> toAccountComboBox;

	private class DirtyListener implements DocumentListener, ItemListener {
		@Override
		public void itemStateChanged(ItemEvent e) {
			handleModification();
		}
		
		@Override
		public void removeUpdate(DocumentEvent e) {
			handleModification();
		}
		
		@Override
		public void insertUpdate(DocumentEvent e) {
			handleModification();
		}
		
		@Override
		public void changedUpdate(DocumentEvent e) {
			handleModification();
		}
		
		private void handleModification() {
			if (getTransactionEditor().isEditing())
				getTransactionEditor().setDirty();
		}
	}
	
	private DirtyListener dirtyListener = new DirtyListener();
	
	protected AbstractTransactionEditorView(TransactionEditor editor) {
		transactionEditor = editor;
		setLayout(new GridBagLayout());
		createContent();
	}

	protected abstract void createContent();
	
	protected DateFormattedTextField getDateField() {
		if (null == dateField)
			createDateField();

		return dateField;
	}

	private void createDateField() {
		dateField = new DateFormattedTextField();
		dateField.setColumns(10);
		dateField.setEnabled(false);
		dateField.getDocument().addDocumentListener(dirtyListener);
	}

	protected JTextField getReferenceField() {
		if (null == referenceField)
			createReferenceField();

		return referenceField;
	}

	private void createReferenceField() {
		referenceField = new JTextField(10);
		referenceField.setEnabled(false);
		referenceField.getDocument().addDocumentListener(dirtyListener);
	}

	protected TwoDecimalTextField getAmountField() {
		if (null == amountField)
			createAmountField();

		return amountField;
	}

	private void createAmountField() {
		amountField = new TwoDecimalTextField();
		amountField.setColumns(10);
		amountField.setEnabled(false);
		amountField.getDocument().addDocumentListener(dirtyListener);
	}

	protected JComboBox<Individual> getIndividualComboBox() {
		if (null == individualComboBox)
			createIndividualComboBox();

		return individualComboBox;
	}

	private void createIndividualComboBox() {
		individualComboBox = new JComboBox<Individual>(new PojoComboBoxModel<Individual>("Individual.getAllIndividuals", Individual.class, true));
		individualComboBox.setEnabled(false);
		individualComboBox.addItemListener(dirtyListener);
	}

	protected JTextField getDescriptionField() {
		if (null == descriptionField)
			createDescriptionField();

		return descriptionField;
	}

	private void createDescriptionField() {
		descriptionField = new JTextField();
		descriptionField.setEnabled(false);
		descriptionField.getDocument().addDocumentListener(dirtyListener);
	}
	
	protected JComboBox<Payee> getPayeeComboBox() {
		if (null == payeeComboBox)
			createPayeeComboBox();
		
		return payeeComboBox;
	}

	private void createPayeeComboBox() {
		payeeComboBox = new JComboBox<Payee>(new PojoComboBoxModel<Payee>("Payee.getAllPayees", Payee.class, true));
		payeeComboBox.setEnabled(false);
		payeeComboBox.addItemListener(dirtyListener);
	}

	protected JComboBox<Category> getCategoryComboBox() {
		if (null == categoryComboBox)
			createCategoryComboBox();
	
		return categoryComboBox;
	}

	private void createCategoryComboBox() {
		categoryComboBox = new JComboBox<Category>(new PojoComboBoxModel<Category>("Category.getAllCategories", Category.class, true));
		categoryComboBox.setEnabled(false);
		categoryComboBox.addItemListener(dirtyListener);
		categoryComboBox.addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent e) {
				Category category = (Category) categoryComboBox.getSelectedItem();
				getSubcategoryComboBox().setModel(new DefaultComboBoxModel<Category>(getSubcategories(category)));
			}
			
			private Category[] getSubcategories(Category parentCategory) {
				if (null == parentCategory)
					return new Category[1];
				
				Category[] subcategories = new Category[parentCategory.getSubCategories().size() + 1];
				for (int i = 0; i < parentCategory.getSubCategories().size(); ++i)
					subcategories[i + 1] = parentCategory.getSubCategories().get(i);
				
				return subcategories;
			}
		});
	}

	protected JComboBox<Category> getSubcategoryComboBox() {
		if (null == subcategoryComboBox)
			createSubcategoryComboBox();
	
		return subcategoryComboBox;
	}

	private void createSubcategoryComboBox() {
		subcategoryComboBox = new JComboBox<Category>();
		subcategoryComboBox.setEnabled(false);
		subcategoryComboBox.addItemListener(dirtyListener);
	}

	protected JComboBox<Account> getFromAccountComboBox() {
		if (null == fromAccountComboBox)
			createFromAccountComboBox();
	
		return fromAccountComboBox;
	}

	private void createFromAccountComboBox() {
		fromAccountComboBox = new JComboBox<Account>(new PojoComboBoxModel<Account>("Account.getAllAccounts", Account.class, false));
		fromAccountComboBox.setEnabled(false);
		fromAccountComboBox.addItemListener(dirtyListener);
	}

	protected JComboBox<Account> getToAccountComboBox() {
		if (null == toAccountComboBox)
			createToAccountComboBox();
	
		return toAccountComboBox;
	}

	private void createToAccountComboBox() {
		toAccountComboBox = new JComboBox<Account>(new PojoComboBoxModel<Account>("Account.getAllAccounts", Account.class, false));
		toAccountComboBox.setEnabled(false);
		toAccountComboBox.addItemListener(dirtyListener);
	}

	protected TransactionEditor getTransactionEditor() {
		return transactionEditor;
	}
	
	protected abstract void beginEditing();
	
	protected abstract void endEditing();
	
	protected abstract void commitChanges();

	abstract void setTransaction(Transaction transaction);
	
	void clearTransaction() {
		getAmountField().setText(null);
		getCategoryComboBox().setSelectedItem(null);
		getDateField().setText(null);
		getDescriptionField().setText(null);
		getFromAccountComboBox().setSelectedItem(null);
		getIndividualComboBox().setSelectedItem(null);
		getPayeeComboBox().setSelectedItem(null);
		getReferenceField().setText(null);
		getSubcategoryComboBox().setSelectedItem(null);
		getToAccountComboBox().setSelectedItem(null);
	}
}
